#include "instructions/references/newarray.h"
#include "rtda/heap/class_loader.h"
#include "rtda/heap/object.h"
#include "rtda/heap/class.h"

namespace jvm {
    namespace instructions {

        void NEW_ARRAY::fetchOperands(std::shared_ptr<BytecodeReader> reader) {
            _atype = reader->readUint8();
        }

        void NEW_ARRAY::execute(std::shared_ptr<rtda::Frame> pframe)
        {
            auto&& stack = pframe->getOperandStack();
            int32_t count = stack->popInt();
            if (count < 0) {
                throw std::runtime_error("java.lang.NegativeArraySizeException");
            }

            auto classLoader = pframe->getMethod()->getClass()->getLoder();
            auto arrClass = getPrimitiveArrayClass(classLoader, _atype);
            auto arr = arrClass->newArray(static_cast<uint32_t>(count));
            stack->pushRef(arr);
        }

        std::shared_ptr<heap::Class> NEW_ARRAY::getPrimitiveArrayClass(std::shared_ptr<heap::ClassLoader> loader, uint8_t atype)
        {
            switch (atype) {
            case AT_BOOLEAN: return loader->loadClass("[Z");
            case AT_BYTE:    return loader->loadClass("[B");
            case AT_CHAR:    return loader->loadClass("[C");
            case AT_SHORT:   return loader->loadClass("[S");
            case AT_INT:     return loader->loadClass("[I");
            case AT_LONG:    return loader->loadClass("[J");
            case AT_FLOAT:   return loader->loadClass("[F");
            case AT_DOUBLE:  return loader->loadClass("[D");
            default:
                throw std::runtime_error("Invalid atype!");
            }
        }

    } // namespace instructions
}// namespace jvm